Skip to content

[https://nvbugs/6388205][fix] Surface crashed trtllm-serve worker log on perf-sanity failures#15837

Closed
Shixiaowei02 wants to merge 1 commit into
NVIDIA:mainfrom
Shixiaowei02:fix/nvbug-6388205-perf-sanity-worker-log
Closed

[https://nvbugs/6388205][fix] Surface crashed trtllm-serve worker log on perf-sanity failures#15837
Shixiaowei02 wants to merge 1 commit into
NVIDIA:mainfrom
Shixiaowei02:fix/nvbug-6388205-perf-sanity-worker-log

Conversation

@Shixiaowei02

@Shixiaowei02 Shixiaowei02 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Description

This pull request improves the reliability and diagnosability of the perf_sanity.py integration test by ensuring that, when a server subprocess crashes or exits unexpectedly, the tail of its log file is echoed to the test output. This makes it much easier to diagnose failures in CI environments where logs might otherwise be lost. The changes also introduce utility functions to detect abnormal server exits and to print log tails, and update the server management logic to use these utilities.

Enhanced error reporting and diagnostics:

  • Added _server_exited_abnormally and _echo_server_log_tail helper functions to detect unexpected server process exits and to print the last lines of server log files for easier debugging.
  • Updated server process handling in the run_cmd method to call these helpers when a server crashes or the test fails, ensuring logs are surfaced in CI outputs. This change is applied to all relevant server types (aggregated, disaggregated, benchmark). [1] [2] [3]

Imports and code organization:

  • Added necessary imports (signal, sys) and updated the import of print_error for improved error output. [1] [2]

Minor code quality improvements:

  • Ensured server process variables are initialized to None before use to avoid potential UnboundLocalError.

Test Coverage

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

Summary by CodeRabbit

  • Bug Fixes
    • Improved test crash handling so failed server subprocesses are easier to diagnose.
    • When a test process exits unexpectedly or an error occurs, the most relevant server log details are now shown in the test output.
    • Added more reliable cleanup and termination behavior for server-related test processes in both aggregated and disaggregated runs.

@Shixiaowei02
Shixiaowei02 requested a review from a team as a code owner July 1, 2026 12:32
@Shixiaowei02
Shixiaowei02 requested a review from chenfeiz0326 July 1, 2026 12:33
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds crash triage logic to the perf sanity test module. Two helper functions detect abnormal subprocess exits and print server log tails via print_error. These are integrated into finally cleanup blocks for aggregated and disaggregated test command execution paths.

Changes

Server Crash Triage in Perf Sanity Tests

Layer / File(s) Summary
Crash triage helpers and imports
tests/integration/defs/perf/test_perf_sanity.py
Adds signal, sys imports and print_error import; introduces _server_exited_abnormally(...) and _echo_server_log_tail(...) helpers to classify abnormal subprocess termination and print log tails.
Aggregated mode cleanup
tests/integration/defs/perf/test_perf_sanity.py
Updates AggrTestCmds.run_cmd finally block to detect exceptions, poll the server return code, terminate/wait, and conditionally echo the log tail.
Disaggregated mode cleanup
tests/integration/defs/perf/test_perf_sanity.py
Initializes server_proc to None; updates finally blocks for the ctx/gen worker branch and DISAGG_SERVER branch to apply the same exception/abnormal-exit detection and log-tail echoing, guarded by is not None checks.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TestRunner
  participant ServerProc
  participant Helpers
  participant LogFile

  TestRunner->>ServerProc: poll return code
  TestRunner->>Helpers: _server_exited_abnormally(returncode)
  Helpers-->>TestRunner: abnormal exit boolean
  TestRunner->>ServerProc: terminate and wait
  alt exception raised or abnormal exit
    TestRunner->>Helpers: _echo_server_log_tail(log_path)
    Helpers->>LogFile: read tail lines
    Helpers->>TestRunner: print_error(log tail)
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the required ticket/type format and clearly summarizes the log-surfacing fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description explains the problem and fix and follows the template closely, though the Test Coverage section is left empty.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/integration/defs/perf/test_perf_sanity.py (2)

1006-1012: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid loading the whole log into memory to tail it.

readlines()[-num_lines:] materializes the entire file before slicing. A crashed trtllm-serve worker can emit very large logs, so this can spike memory (or OOM) exactly during CI triage. Iterating with a bounded deque keeps only the last num_lines in memory.

♻️ Bounded tail read
+from collections import deque
+
 ...
     try:
-        with open(log_path, "r", errors="replace") as log_file:
-            tail = "".join(log_file.readlines()[-num_lines:])
+        with open(log_path, "r", errors="replace") as log_file:
+            tail = "".join(deque(log_file, maxlen=num_lines))
     except OSError as err:

(Place the deque import with the other top-of-file imports.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/defs/perf/test_perf_sanity.py` around lines 1006 - 1012,
The log tailing logic in the server log helper currently uses
readlines()[-num_lines:], which loads the entire file into memory before
slicing. Update the log-reading path to use a bounded deque for tailing instead,
and add the deque import alongside the other top-level imports. Keep the
existing OSError handling and print_error behavior in the same helper, but
ensure only the last num_lines lines are retained in memory.

1116-1131: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

wait() has no timeout and SIGKILL escalation never happens.

server_proc.terminate() sends only SIGTERM, then server_proc.wait() blocks unbounded. If the worker ignores SIGTERM (common for a hung server that is exactly what you're trying to triage), cleanup hangs indefinitely and the log tail is never printed. Note _server_exited_abnormally and its docstring already anticipate -SIGKILL, but nothing here escalates to kill().

This same block is duplicated in the ctx/gen branch (Lines 1344-1354) and the DISAGG_SERVER branch (Lines 1379-1389). Extracting a single helper resolves the hang and the duplication together.

♻️ Shared terminate-with-escalation helper
def _shutdown_and_maybe_echo(proc, log_path, label):
    raising = sys.exc_info()[0] is not None
    pre_rc = proc.poll()
    proc.terminate()
    try:
        rc = proc.wait(timeout=30)
    except subprocess.TimeoutExpired:
        proc.kill()
        rc = proc.wait()
    if raising or _server_exited_abnormally(pre_rc, rc):
        _echo_server_log_tail(log_path, label, pre_rc if pre_rc is not None else rc)

Then each finally reduces to a guarded call, e.g.:

         finally:
             if server_proc:
-                raising = sys.exc_info()[0] is not None
-                pre_rc = server_proc.poll()
-                server_proc.terminate()
-                rc = server_proc.wait()
-                if raising or _server_exited_abnormally(pre_rc, rc):
-                    _echo_server_log_tail(
-                        server_file_path,
-                        f"aggr:{server_idx}",
-                        pre_rc if pre_rc is not None else rc,
-                    )
+                _shutdown_and_maybe_echo(
+                    server_proc, server_file_path, f"aggr:{server_idx}"
+                )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/defs/perf/test_perf_sanity.py` around lines 1116 - 1131,
The shutdown path in the server cleanup block can hang indefinitely because
`server_proc.wait()` has no timeout and never escalates past SIGTERM. Update the
cleanup logic around `server_proc.terminate()` in this `finally` block, and in
the duplicated ctx/gen and `DISAGG_SERVER` branches, to use a shared helper (for
example, a `_shutdown_and_maybe_echo`-style routine) that waits with a timeout,
calls `server_proc.kill()` on timeout, then waits again before deciding whether
to call `_echo_server_log_tail`. Keep the existing `_server_exited_abnormally`
check and reuse the current `pre_rc`/`rc` handling so the log tail still prints
on failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/integration/defs/perf/test_perf_sanity.py`:
- Around line 1006-1012: The log tailing logic in the server log helper
currently uses readlines()[-num_lines:], which loads the entire file into memory
before slicing. Update the log-reading path to use a bounded deque for tailing
instead, and add the deque import alongside the other top-level imports. Keep
the existing OSError handling and print_error behavior in the same helper, but
ensure only the last num_lines lines are retained in memory.
- Around line 1116-1131: The shutdown path in the server cleanup block can hang
indefinitely because `server_proc.wait()` has no timeout and never escalates
past SIGTERM. Update the cleanup logic around `server_proc.terminate()` in this
`finally` block, and in the duplicated ctx/gen and `DISAGG_SERVER` branches, to
use a shared helper (for example, a `_shutdown_and_maybe_echo`-style routine)
that waits with a timeout, calls `server_proc.kill()` on timeout, then waits
again before deciding whether to call `_echo_server_log_tail`. Keep the existing
`_server_exited_abnormally` check and reuse the current `pre_rc`/`rc` handling
so the log tail still prints on failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e27fc96f-d898-497c-bbcc-d4b7bf4dc79b

📥 Commits

Reviewing files that changed from the base of the PR and between d567f92 and fdf2e07.

📒 Files selected for processing (1)
  • tests/integration/defs/perf/test_perf_sanity.py

@Shixiaowei02
Shixiaowei02 force-pushed the fix/nvbug-6388205-perf-sanity-worker-log branch from fdf2e07 to e31e491 Compare July 1, 2026 13:07
…serve worker log on perf-sanity failures

Disaggregated perf-sanity tests redirect each trtllm-serve (ctx/gen/disagg)
subprocess's stdout+stderr into a file under the test output dir and never
stream it to the pytest console. When a worker fails -- it crashes on its own,
never becomes ready (timeout), or hangs -- the run_cmd finally blocks only
terminate()/wait() the process, so its real error dies with the temporary slurm
node; triage sees only "Test terminated unexpectedly" and empty stdout/stderr
in the CI Report DB (NVBug 6388205).

In each of the three server-owning finally blocks (AggrTestCmds.run_cmd and the
ctx/gen and DISAGG_SERVER paths of DisaggTestCmds.run_cmd), when the test is
failing (an exception is propagating) or the server exited abnormally on its
own, echo the tail of the corresponding trtllm-serve.*.log via print_error
(which also logs to general_logger -> Jenkins Raw Log -> CI Report DB stderr).
The message states how the worker failed -- 'crashed on its own (returncode=N)'
vs 'terminated by the harness after the test failed ... timeout or hang' -- plus
the propagating failure reason, so all three modes are clear. Also initialize the
disagg proc handles to None so those finally blocks no longer risk NameError.

Signed-off-by: Shixiaowei02 <39303645+Shixiaowei02@users.noreply.github.com>
@Shixiaowei02
Shixiaowei02 force-pushed the fix/nvbug-6388205-perf-sanity-worker-log branch from e31e491 to 4d1bc2a Compare July 2, 2026 07:43
@Shixiaowei02

Copy link
Copy Markdown
Collaborator Author

/bot run  --disable-fail-fast --stage-list "*GB200*PerfSanity*,*GB300*PerfSanity*"

@Shixiaowei02
Shixiaowei02 requested review from chuangz0 and nv-xtf July 2, 2026 07:45
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57165 Bot args parsing error: usage: /bot [-h]
{run,kill,skip,submit,reviewers,reuse-pipeline,reuse-review} ...
/bot: error: argument action: invalid choice: 'run\xa0' (choose from 'run', 'kill', 'skip', 'submit', 'reviewers', 'reuse-pipeline', 'reuse-review')

Link to invocation

@Shixiaowei02

Copy link
Copy Markdown
Collaborator Author

/bot -h

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

GitHub Bot Help

/bot [-h] ['run', 'kill', 'skip', 'reuse-pipeline'] ...

Provide a user friendly way for developers to interact with a Jenkins server.

Run /bot [-h|--help] to print this help message.

See details below for each supported subcommand.

Details

run [--reuse-test (optional)pipeline-id --disable-fail-fast --skip-test --stage-list "A10-PyTorch-1, xxx" --gpu-type "A30, H100_PCIe" --test-backend "pytorch, cpp" --add-multi-gpu-test --only-multi-gpu-test --disable-multi-gpu-test --post-merge --extra-stage "H100_PCIe-TensorRT-Post-Merge-1, xxx" --detailed-log --debug(experimental) --high-priority]

Launch build/test pipelines. All previously running jobs will be killed.

--reuse-test (optional)pipeline-id (OPTIONAL) : Allow the new pipeline to reuse build artifacts and skip successful test stages from a specified pipeline or the last pipeline if no pipeline-id is indicated. If the Git commit ID has changed, this option will be always ignored. The DEFAULT behavior of the bot is to reuse build artifacts and successful test results from the last pipeline.

--disable-reuse-test (OPTIONAL) : Explicitly prevent the pipeline from reusing build artifacts and skipping successful test stages from a previous pipeline. Ensure that all builds and tests are run regardless of previous successes.

--disable-fail-fast (OPTIONAL) : Disable fail fast on build/tests/infra failures.

--skip-test (OPTIONAL) : Skip all test stages, but still run build stages, package stages and sanity check stages. Note: Does NOT update GitHub check status.

--stage-list "A10-PyTorch-1, xxx" (OPTIONAL) : Only run the specified test stages. Supports wildcard * for pattern matching (e.g., "*PerfSanity*" matches all stages containing PerfSanity). Examples: "A10-PyTorch-1, xxx", "PerfSanity". Note: Does NOT update GitHub check status.

--gpu-type "A30, H100_PCIe" (OPTIONAL) : Only run the test stages on the specified GPU types. Examples: "A30, H100_PCIe". Note: Does NOT update GitHub check status.

--test-backend "pytorch, cpp" (OPTIONAL) : Skip test stages which don't match the specified backends. Only support [pytorch, cpp, tensorrt, triton]. Examples: "pytorch, cpp" (does not run test stages with tensorrt or triton backend). Note: Does NOT update GitHub pipeline status.

--only-multi-gpu-test (OPTIONAL) : Only run the multi-GPU tests. Note: Does NOT update GitHub check status.

--disable-multi-gpu-test (OPTIONAL) : Disable the multi-GPU tests. Note: Does NOT update GitHub check status.

--add-multi-gpu-test (OPTIONAL) : Force run the multi-GPU tests in addition to running L0 pre-merge pipeline.

--post-merge (OPTIONAL) : Run the L0 post-merge pipeline instead of the ordinary L0 pre-merge pipeline.

--extra-stage "H100_PCIe-TensorRT-Post-Merge-1, xxx" (OPTIONAL) : Run the ordinary L0 pre-merge pipeline and specified test stages. Supports wildcard * for pattern matching. Examples: --extra-stage "H100_PCIe-TensorRT-Post-Merge-1, xxx", --extra-stage "Post-Merge".

--detailed-log (OPTIONAL) : Enable flushing out all logs to the Jenkins console. This will significantly increase the log volume and may slow down the job.

--debug (OPTIONAL) : Experimental feature. Enable access to the CI container for debugging purpose. Note: Specify exactly one stage in the stage-list parameter to access the appropriate container environment. Note: Does NOT update GitHub check status.

--high-priority (OPTIONAL) : Run the pipeline with high priority. This option is restricted to authorized users only and will route the job to a high-priority queue.

kill

kill

Kill all running builds associated with pull request.

skip

skip --comment COMMENT

Skip testing for latest commit on pull request. --comment "Reason for skipping build/test" is required. IMPORTANT NOTE: This is dangerous since lack of user care and validation can cause top of tree to break.

reuse-pipeline

reuse-pipeline

Reuse a previous pipeline to validate current commit. This action will also kill all currently running builds associated with the pull request. IMPORTANT NOTE: This is dangerous since lack of user care and validation can cause top of tree to break.

@Shixiaowei02

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --stage-list "GB200PerfSanity*,GB300PerfSanity*"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57170 [ run ] triggered by Bot. Commit: 4d1bc2a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57170 [ run ] completed with state FAILURE. Commit: 4d1bc2a
/LLM/main/L0_MergeRequest_PR pipeline #45945 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants